package cn.kone.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.kone.mapper.LoginMapper;
import cn.kone.pojo.domain.Login;
import cn.kone.service.ILoginService;
import cn.kone.service.IPermissionService;
import cn.kone.template.WechatTemplate;
import cn.kone.util.GtUtil;
import cn.kone.utils.AssertUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author yuyu
 * @since 2024-03-16
 */
@Service
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {


    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WechatTemplate wechatTemplate;

    @Override
    public Object login(String code,String type) {
/**
 * appid自己的微信小程序id
 * secret是小程序的秘钥
 * js_code是前端传递过来的Code
 * https://api.weixin.qq.com/sns/jscode2session?appid=wx76a39daa4e95dca8&secret=54ca332e7c4d0bc391cc24d1fcdfdc89&js_code=" + code + "&grant_type=authorization_code
 */
        // 发起 HTTP GET 请求，获取用户的 OpenID
//        String getOpenIdUrl = HttpUtil.get("https://api.weixin.qq.com/sns/jscode2session?appid="
//                + appId + "&secret=" + appSecret +
//                "&js_code=" + code + "&grant_type=authorization_code");
//        // 将获取到的响应结果解析为 JSON 对象
//        JSONObject jsonObject = JSONObject.parseObject(getOpenIdUrl, JSONObject.class);
//        // 从 JSON 对象中获取用户的 OpenID
//        String openid = jsonObject.getString("openid");


//        String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+appId+"&secret="+appSecret+"&js_code=" + code + "&grant_type=authorization_code";
//        //发送请求获取openId
//        String text = restTemplate.getForObject(url, String.class);
//        //将得到的参数存进map里面
//        Map map = JSON.parseObject(text, Map.class);
//        //获取到openid
//        String openid = (String) map.get("openid");
//        //打印看看结果是怎样的
//        System.out.println(openid);

        //通过自定义starter封装了通过code获取openid的方法这里是可以直接注入使用
        String openid = wechatTemplate.getOpenId(code);

        // 通过 openid 查询数据库中是否已存在对应的司机信息
        Login one = getOne(new LambdaQueryWrapper<Login>().eq(Login::getOpenId, openid).eq(Login::getType,type));
        // 如果查询结果不为空，表示已经存在相同 openid 的司机信息，如果查询结果不为空，则抛出异常并提供提示信息
        AssertUtil.isNotNull(one, "滚去注册!!!");

        // 使用用户ID进行登录，将用户信息与Token绑定
        StpUtil.login(one.getId());

        // 获取当前登录用户的Token信息
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        // 获取Token的值
        String tokenValue = tokenInfo.getTokenValue();

        //将下单人的信息存储在redis中,key的值是one+用户的登陆id(司机是司机的,乘客是乘客的已做区分)
        redisTemplate.boundValueOps("one"+StpUtil.getLoginIdAsLong()).set(one);

        // 返回Token值
        return tokenValue;
    }


    /**
     * admin 平台用户登陆实现
     *
     * @param login
     * @return
     */

    @Override
    public Object admin(Login login) {
        //1.首先查询数据库中admin的用户信息
        // 使用 LambdaQueryWrapper 构建查询条件，这里的 Login 是实体类
        // 添加查询条件：username 字段等于传入的 login 对象的 username 属性值
        // 调用 getOne 方法执行查询，获取符合条件的一条 Login 记录，并将结果赋值给 admin 变量
        Login admin = getOne(new LambdaQueryWrapper<Login>().eq(Login::getUsername, login.getUsername()));
        //2.检验用户名是否存在
        AssertUtil.isNotNull(admin, "该用户不存在~~");
        //3.校验密码是否正确
        boolean checkpwed = BCrypt.checkpw(login.getPassword(), admin.getPassword());
        AssertUtil.isTrue(checkpwed, "密码错误请重试~~");
        //4.校验成功以后就生成登陆的SaToken令牌
        StpUtil.login(admin.getId());
        //5.获取token信息tokenValue里面就是SaToken令牌
        String tokenValue = StpUtil.getTokenInfo().getTokenValue();
        //6.创建一个Map将前端需要的信息封装进去统一返回给前端
        Map map = new HashMap();
        map.put("satoken", tokenValue); //token令牌
        admin.setPassword(null); //脱敏
        map.put("login", admin); //用户的信息
        // 获取管理员的权限列表
        List<String> permissions = permissionService.getPermissions(String.valueOf(admin.getId()));
        map.put("permissions", permissions);
        return map;
    }

    /**
     * 平台用户退出登录
     * 该方法用于处理平台用户的退出登录操作。
     * 它从 Redis 缓存中移除与已登录用户关联的权限和会话数据。
     *
     * @return null，因为此方法没有特定的返回值
     */
    @Override
    public Object outLogin() {
        // 从 Redis 缓存中删除与已登录用户关联的权限
        redisTemplate.delete("permissions" + StpUtil.getLoginId());
        // 从 Redis 缓存中删除与已登录用户关联的会话数据
        redisTemplate.delete(StpUtil.getLoginId());
        // 使用 StpUtil 库注销用户
        StpUtil.logout(StpUtil.getLoginId());
        return null;
    }


    //前端发送请求用来绑定cid和uid
    @Override
    public Object bindCidAndUid(String cid) {
        return GtUtil.getuiBind(cid);
    }
}

